;(function ($, window, document, undefined) {
  'use strict'

  var defaults = {
    mode: 'tglider-slide',

    // Ex : 'ease'
    cssEasing: 'ease',

    //'for jquery animation'
    easing: 'linear',
    speed: 600,
    height: '100%',
    width: '100%',
    addClass: '',
    startClass: 'tglider-start-zoom',
    backdropDuration: 150,
    hideBarsDelay: 6000,

    useLeft: false,

    closable: true,
    loop: false,
    escKey: true,
    keyPress: true,
    controls: true,
    slideEndAnimatoin: true,
    hideControlOnEnd: true,
    mousewheel: true,

    // .tglider-item || '.tglider-sub-html'
    appendSubHtmlTo: '.tglider-sub-html',
    getCaptionFromTitleOrAlt: false,

    /**
     * @desc number of preload slides
     * will exicute only after the current slide is fully loaded.
     *
     * @ex you clicked on 4th image and if preload = 1 then 3rd slide and 5th
     * slide will be loaded in the background after the 4th slide is fully loaded..
     * if preload is 2 then 2nd 3rd 5th 6th slides will be preloaded.. ... ...
     *
     */
    preload: 1,
    showAfterLoad: true,
    showThumbByDefault: false,
    selector: '',
    selectWithin: '',
    nextHtml: '',
    prevHtml: '',

    // 0, 1
    index: false,

    iframeMaxWidth: '100%',

    download: false,
    counter: true,
    appendCounterTo: '.tglider-toolbar',

    swipeThreshold: 50,
    enableSwipe: true,
    enableDrag: true,

    dynamic: false,
    dynamicEl: [],
    galleryId: 1,
  }

  function Plugin(element, options) {
    // Current tangibleGlider element
    this.el = element

    // Current jquery element
    this.$el = $(element)

    // tangibleGlider settings
    this.s = $.extend({}, defaults, options)

    // When using dynamic mode, ensure dynamicEl is an array
    if (
      this.s.dynamic &&
      this.s.dynamicEl !== 'undefined' &&
      this.s.dynamicEl.constructor === Array &&
      !this.s.dynamicEl.length
    ) {
      throw 'When using dynamic mode, you must also define dynamicEl as an Array.'
    }

    // tangibleGlider modules
    this.modules = {}

    // false when lightgallery complete first slide;
    this.lGalleryOn = false

    this.lgBusy = false

    // Timeout function for hiding controls;
    this.hideBartimeout = false

    // To determine browser supports for touch events;
    this.isTouch = 'ontouchstart' in document.documentElement

    // Disable hideControlOnEnd if sildeEndAnimation is true
    /*        if (this.s.slideEndAnimatoin) {
            this.s.hideControlOnEnd = false;
        }
*/
    // Gallery items
    if (this.s.dynamic) {
      this.$items = this.s.dynamicEl
    } else {
      if (this.s.selector === 'this') {
        this.$items = this.$el
      } else if (this.s.selector !== '') {
        if (this.s.selectWithin) {
          this.$items = $(this.s.selectWithin).find(this.s.selector)
        } else {
          this.$items = this.$el.find($(this.s.selector))
        }
      } else {
        this.$items = this.$el.children()
      }

      // Filter out containers without image
      this.$items = this.$items.filter(function () {
        return $(this).find('img').length
      })
    }

    // .tglider-item
    this.$slide = ''

    // .tglider-outer
    this.$outer = ''

    this.init()

    return this
  }

  Plugin.prototype.init = function () {
    var _this = this

    // s.preload should not be more than $item.length
    if (_this.s.preload > _this.$items.length) {
      _this.s.preload = _this.$items.length
    }

    // if dynamic option is enabled execute immediately
    var _hash = window.location.hash
    if (_hash.indexOf('lg=' + this.s.galleryId) > 0) {
      _this.index = parseInt(_hash.split('&slide=')[1], 10)

      $('body').addClass('tglider-from-hash')
      if (!$('body').hasClass('tglider-on')) {
        setTimeout(function () {
          _this.build(_this.index)
          $('body').addClass('tglider-on')
        })
      }
    }

    if (_this.s.dynamic) {
      _this.$el.trigger('onBeforeOpen.lg')

      _this.index = _this.s.index || 0

      // prevent accidental double execution
      if (!$('body').hasClass('tglider-on')) {
        setTimeout(function () {
          _this.build(_this.index)
          $('body').addClass('tglider-on')
        })
      }
    } else {
      // Using different namespace for click because click event should not unbind if selector is same object('this')
      _this.$items.on('click.lgcustom', function (event) {
        // For IE8
        try {
          event.preventDefault()
          event.preventDefault()
        } catch (er) {
          event.returnValue = false
        }

        _this.$el.trigger('onBeforeOpen.lg')

        _this.index = _this.s.index || _this.$items.index(this)

        // prevent accidental double execution
        if (!$('body').hasClass('tglider-on')) {
          _this.build(_this.index)
          $('body').addClass('tglider-on')
        }
      })
    }
  }

  Plugin.prototype.build = function (index) {
    var _this = this

    _this.structure()

    // module constructor
    $.each($.fn.tangibleGlider.modules, function (key) {
      _this.modules[key] = new $.fn.tangibleGlider.modules[key](_this.el)
    })

    // initiate slide function
    _this.slide(index, false, false)

    if (_this.s.keyPress) {
      _this.keyPress()
    }

    if (_this.$items.length > 1) {
      _this.arrow()

      setTimeout(function () {
        _this.enableDrag()
        _this.enableSwipe()
      }, 50)

      if (_this.s.mousewheel) {
        _this.mousewheel()
      }
    }

    _this.counter()

    _this.closeGallery()

    _this.$el.trigger('onAfterOpen.lg')

    // Hide controllers if mouse doesn't move for some period
    _this.$outer.on('mousemove.lg click.lg touchstart.lg', function () {
      _this.$outer.removeClass('tglider-hide-items')

      clearTimeout(_this.hideBartimeout)

      // Timeout will be cleared on each slide movement also
      _this.hideBartimeout = setTimeout(function () {
        _this.$outer.addClass('tglider-hide-items')
      }, _this.s.hideBarsDelay)
    })
  }

  Plugin.prototype.structure = function () {
    var list = ''
    var controls = ''
    var i = 0
    var subHtmlCont = ''
    var template
    var _this = this

    $('body').append('<div class="tglider-backdrop"></div>')
    $('.tglider-backdrop').css(
      'transition-duration',
      this.s.backdropDuration + 'ms'
    )

    // Create gallery items
    for (i = 0; i < this.$items.length; i++) {
      list += '<div class="tglider-item"></div>'
    }

    // Create controlls
    if (this.s.controls && this.$items.length > 1) {
      controls =
        '<div class="tglider-actions">' +
        '<div class="tglider-prev tglider-icon">' +
        this.s.prevHtml +
        '</div>' +
        '<div class="tglider-next tglider-icon">' +
        this.s.nextHtml +
        '</div>' +
        '</div>'
    }

    if (this.s.appendSubHtmlTo === '.tglider-sub-html') {
      subHtmlCont = '<div class="tglider-sub-html"></div>'
    }

    template =
      '<div class="tglider-outer ' +
      this.s.addClass +
      ' ' +
      this.s.startClass +
      '">' +
      '<div class="lg" style="width:' +
      this.s.width +
      '; height:' +
      this.s.height +
      '">' +
      '<div class="tglider-inner">' +
      list +
      '</div>' +
      '<div class="tglider-toolbar group">' +
      '<span class="tglider-close tglider-icon"></span>' +
      '</div>' +
      controls +
      subHtmlCont +
      '</div>' +
      '</div>'

    $('body').append(template)
    this.$outer = $('.tglider-outer')
    this.$slide = this.$outer.find('.tglider-item')

    if (this.s.useLeft) {
      this.$outer.addClass('tglider-use-left')

      // Set mode tglider-slide if use left is true;
      this.s.mode = 'tglider-slide'
    } else {
      this.$outer.addClass('tglider-use-css3')
    }

    // For fixed height gallery
    _this.setTop()
    $(window).on('resize.lg orientationchange.lg', function () {
      setTimeout(function () {
        _this.setTop()
      }, 100)
    })

    // add class tglider-current to remove initial transition
    this.$slide.eq(this.index).addClass('tglider-current')

    // add Class for css support and transition mode
    if (this.doCss()) {
      this.$outer.addClass('tglider-css3')
    } else {
      this.$outer.addClass('tglider-css')

      // Set speed 0 because no animation will happen if browser doesn't support css3
      this.s.speed = 0
    }

    this.$outer.addClass(this.s.mode)

    if (this.s.enableDrag && this.$items.length > 1) {
      this.$outer.addClass('tglider-grab')
    }

    if (this.s.showAfterLoad) {
      this.$outer.addClass('tglider-show-after-load')
    }

    if (this.doCss()) {
      var $inner = this.$outer.find('.tglider-inner')
      $inner.css('transition-timing-function', this.s.cssEasing)
      $inner.css('transition-duration', this.s.speed + 'ms')
    }

    $('.tglider-backdrop').addClass('in')

    setTimeout(function () {
      _this.$outer.addClass('tglider-visible')
    }, this.s.backdropDuration)

    if (this.s.download) {
      this.$outer
        .find('.tglider-toolbar')
        .append(
          '<a id="tglider-download" target="_blank" download class="tglider-download tglider-icon"></a>'
        )
    }

    // Store the current scroll top value to scroll back after closing the gallery..
    this.prevScrollTop = $(window).scrollTop()
  }

  // For fixed height gallery
  Plugin.prototype.setTop = function () {
    if (this.s.height !== '100%') {
      var wH = $(window).height()
      var top = (wH - parseInt(this.s.height, 10)) / 2
      var $lGallery = this.$outer.find('.lg')
      if (wH >= parseInt(this.s.height, 10)) {
        $lGallery.css('top', top + 'px')
      } else {
        $lGallery.css('top', '0px')
      }
    }
  }

  // Find css3 support
  Plugin.prototype.doCss = function () {
    // check for css animation support
    var support = function () {
      var transition = [
        'transition',
        'MozTransition',
        'WebkitTransition',
        'OTransition',
        'msTransition',
        'KhtmlTransition',
      ]
      var root = document.documentElement
      var i = 0
      for (i = 0; i < transition.length; i++) {
        if (transition[i] in root.style) {
          return true
        }
      }
    }

    if (support()) {
      return true
    }

    return false
  }

  /**
   *  @desc Check the given src is video
   *  @param {String} src
   *  @return {Object} video type
   *  Ex:{ youtube  :  ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
   */
  Plugin.prototype.isVideo = function (src, index) {
    var html
    if (this.s.dynamic) {
      html = this.s.dynamicEl[index].html
    } else {
      html = this.$items.eq(index).attr('data-html')
    }

    if (!src) {
      if (html) {
        return {
          html5: true,
        }
      } else return
    }

    var youtube = src.match(
      /\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)/i
    )
    var vimeo = src.match(/\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i)
    var dailymotion = src.match(/\/\/(?:www\.)?dai.ly\/([0-9a-z\-_]+)/i)
    var vk = src.match(
      /\/\/(?:www\.)?(?:vk\.com|vkontakte\.ru)\/(?:video_ext\.php\?)(.*)/i
    )

    if (youtube) {
      return {
        youtube: youtube,
      }
    } else if (vimeo) {
      return {
        vimeo: vimeo,
      }
    } else if (dailymotion) {
      return {
        dailymotion: dailymotion,
      }
    } else if (vk) {
      return {
        vk: vk,
      }
    }
  }

  /**
   *  @desc Create image counter
   *  Ex: 1/10
   */
  Plugin.prototype.counter = function () {
    if (this.s.counter) {
      if (this.$items.length > 1) {
        $(this.s.appendCounterTo).append(
          '<div id="tglider-counter"><span id="tglider-counter-current">' +
            (parseInt(this.index, 10) + 1) +
            '</span> / <span id="tglider-counter-all">' +
            this.$items.length +
            '</span></div>'
        )
      }
    }
  }

  /**
   *  @desc add sub-html into the slide
   *  @param {Number} index - index of the slide
   */
  Plugin.prototype.addHtml = function (index) {
    var subHtml = null
    var subHtmlUrl
    if (this.s.dynamic) {
      if (this.s.dynamicEl[index].subHtmlUrl) {
        subHtmlUrl = this.s.dynamicEl[index].subHtmlUrl
      } else {
        subHtml = this.s.dynamicEl[index].subHtml
      }
    } else {
      if (this.$items.eq(index).attr('data-sub-html-url')) {
        subHtmlUrl = this.$items.eq(index).attr('data-sub-html-url')
      } else {
        subHtml = this.$items.eq(index).attr('data-sub-html')
        if (this.s.getCaptionFromTitleOrAlt && !subHtml) {
          subHtml =
            this.$items.eq(index).attr('title') ||
            this.$items.eq(index).find('img').first().attr('alt')
        }
      }
    }

    if (!subHtmlUrl) {
      if (typeof subHtml !== 'undefined' && subHtml !== null) {
        // get first letter of subhtml
        // if first letter starts with . or # get the html form the jQuery object
        var fL = subHtml.substring(0, 1)
        if (fL === '.' || fL === '#') {
          subHtml = $(subHtml).html()
        } else {
          subHtml = subHtml
        }
      } else {
        subHtml = ''
      }
    }

    if (this.s.appendSubHtmlTo === '.tglider-sub-html') {
      if (subHtmlUrl) {
        this.$outer.find(this.s.appendSubHtmlTo).load(subHtmlUrl)
      } else {
        this.$outer.find(this.s.appendSubHtmlTo).html(subHtml)
      }
    } else {
      if (subHtmlUrl) {
        this.$slide.eq(index).load(subHtmlUrl)
      } else {
        this.$slide.eq(index).append(subHtml)
      }
    }

    // Add tglider-empty-html class if title doesn't exist
    if (typeof subHtml !== 'undefined' && subHtml !== null) {
      if (subHtml === '') {
        this.$outer.find(this.s.appendSubHtmlTo).addClass('tglider-empty-html')
      } else {
        this.$outer
          .find(this.s.appendSubHtmlTo)
          .removeClass('tglider-empty-html')
      }
    }

    this.$el.trigger('onAfterAppendSubHtml.lg', [index])
  }

  /**
   *  @desc Preload slides
   *  @param {Number} index - index of the slide
   */
  Plugin.prototype.preload = function (index) {
    var i = 1
    var j = 1
    for (i = 1; i <= this.s.preload; i++) {
      if (i >= this.$items.length - index) {
        break
      }

      this.loadContent(index + i, false, 0)
    }

    for (j = 1; j <= this.s.preload; j++) {
      if (index - j < 0) {
        break
      }

      this.loadContent(index - j, false, 0)
    }
  }

  /**
   *  @desc Load slide content into slide.
   *  @param {Number} index - index of the slide.
   *  @param {Boolean} rec - if true call loadcontent() function again.
   *  @param {Boolean} delay - delay for adding complete class. it is 0 except first time.
   */
  Plugin.prototype.loadContent = function (index, rec, delay) {
    var _this = this
    var _hasPoster = false
    var _$img
    var _src
    var _poster
    var _srcset
    var _sizes
    var _html
    var getResponsiveSrc = function (srcItms) {
      var rsWidth = []
      var rsSrc = []
      for (var i = 0; i < srcItms.length; i++) {
        var __src = srcItms[i].split(' ')

        // Manage empty space
        if (__src[0] === '') {
          __src.splice(0, 1)
        }

        rsSrc.push(__src[0])
        rsWidth.push(__src[1])
      }

      var wWidth = $(window).width()
      for (var j = 0; j < rsWidth.length; j++) {
        if (parseInt(rsWidth[j], 10) > wWidth) {
          _src = rsSrc[j]
          break
        }
      }
    }

    if (_this.s.dynamic) {
      if (_this.s.dynamicEl[index].poster) {
        _hasPoster = true
        _poster = _this.s.dynamicEl[index].poster
      }

      _html = _this.s.dynamicEl[index].html
      _src = _this.s.dynamicEl[index].src

      if (_this.s.dynamicEl[index].responsive) {
        var srcDyItms = _this.s.dynamicEl[index].responsive.split(',')
        getResponsiveSrc(srcDyItms)
      }

      _srcset = _this.s.dynamicEl[index].srcset
      _sizes = _this.s.dynamicEl[index].sizes
    } else {
      if (_this.$items.eq(index).attr('data-poster')) {
        _hasPoster = true
        _poster = _this.$items.eq(index).attr('data-poster')
      }

      _html = _this.$items.eq(index).attr('data-html')
      _src =
        _this.$items.eq(index).attr('href') ||
        _this.$items.eq(index).attr('data-src') ||
        _this.$items.eq(index).find('a').attr('href')

      if (_this.$items.eq(index).attr('data-responsive')) {
        var srcItms = _this.$items.eq(index).attr('data-responsive').split(',')
        getResponsiveSrc(srcItms)
      }

      _srcset = _this.$items.eq(index).attr('data-srcset')
      _sizes = _this.$items.eq(index).attr('data-sizes')
    }

    //if (_src || _srcset || _sizes || _poster) {

    var iframe = false
    if (_this.s.dynamic) {
      if (_this.s.dynamicEl[index].iframe) {
        iframe = true
      }
    } else {
      if (_this.$items.eq(index).attr('data-iframe') === 'true') {
        iframe = true
      }
    }

    var _isVideo = _this.isVideo(_src, index)
    if (!_this.$slide.eq(index).hasClass('tglider-loaded')) {
      if (iframe) {
        _this.$slide
          .eq(index)
          .prepend(
            '<div class="tglider-video-cont" style="max-width:' +
              _this.s.iframeMaxWidth +
              '"><div class="tglider-video"><iframe class="tglider-object" frameborder="0" src="' +
              _src +
              '"  allowfullscreen="true"></iframe></div></div>'
          )
      } else if (_hasPoster) {
        var videoClass = ''
        if (_isVideo && _isVideo.youtube) {
          videoClass = 'tglider-has-youtube'
        } else if (_isVideo && _isVideo.vimeo) {
          videoClass = 'tglider-has-vimeo'
        } else {
          videoClass = 'tglider-has-html5'
        }

        _this.$slide
          .eq(index)
          .prepend(
            '<div class="tglider-video-cont ' +
              videoClass +
              ' "><div class="tglider-video"><span class="tglider-video-play"></span><img class="tglider-object tglider-has-poster" src="' +
              _poster +
              '" /></div></div>'
          )
      } else if (_isVideo) {
        _this.$slide
          .eq(index)
          .prepend(
            '<div class="tglider-video-cont "><div class="tglider-video"></div></div>'
          )
        _this.$el.trigger('hasVideo.lg', [index, _src, _html])
      } else {
        _this.$slide
          .eq(index)
          .prepend(
            '<div class="tglider-img-wrap"><img class="tglider-object tglider-image" src="' +
              _src +
              '" /></div>'
          )
      }

      _this.$el.trigger('onAferAppendSlide.lg', [index])

      _$img = _this.$slide.eq(index).find('.tglider-object')
      if (_sizes) {
        _$img.attr('sizes', _sizes)
      }

      if (_srcset) {
        _$img.attr('srcset', _srcset)
        try {
          picturefill({
            elements: [_$img[0]],
          })
        } catch (e) {
          console.error('Make sure you have included Picturefill version 2')
        }
      }

      if (this.s.appendSubHtmlTo !== '.tglider-sub-html') {
        _this.addHtml(index)
      }

      _this.$slide.eq(index).addClass('tglider-loaded')
    }

    _this.$slide
      .eq(index)
      .find('.tglider-object')
      .on('load.lg error.lg', function () {
        // For first time add some delay for displaying the start animation.
        var _speed = 0

        // Do not change the delay value because it is required for zoom plugin.
        // If gallery opened from direct url (hash) speed value should be 0
        if (delay && !$('body').hasClass('tglider-from-hash')) {
          _speed = delay
        }

        setTimeout(function () {
          _this.$slide.eq(index).addClass('tglider-complete')
          _this.$el.trigger('onSlideItemLoad.lg', [index, delay || 0])
        }, _speed)
      })

    // @todo check load state for html5 videos
    if (_isVideo && _isVideo.html5 && !_hasPoster) {
      _this.$slide.eq(index).addClass('tglider-complete')
    }

    if (rec === true) {
      if (!_this.$slide.eq(index).hasClass('tglider-complete')) {
        _this.$slide
          .eq(index)
          .find('.tglider-object')
          .on('load.lg error.lg', function () {
            _this.preload(index)
          })
      } else {
        _this.preload(index)
      }
    }

    //}
  }

  /**
    *   @desc slide function for lightgallery
        ** Slide() gets call on start
        ** ** Set lg.on true once slide() function gets called.
        ** Call loadContent() on slide() function inside setTimeout
        ** ** On first slide we do not want any animation like slide of fade
        ** ** So on first slide( if lg.on if false that is first slide) loadContent() should start loading immediately
        ** ** Else loadContent() should wait for the transition to complete.
        ** ** So set timeout s.speed + 50
    <=> ** loadContent() will load slide content in to the particular slide
        ** ** It has recursion (rec) parameter. if rec === true loadContent() will call preload() function.
        ** ** preload will execute only when the previous slide is fully loaded (images iframe)
        ** ** avoid simultaneous image load
    <=> ** Preload() will check for s.preload value and call loadContent() again accoring to preload value
        ** loadContent()  <====> Preload();

    *   @param {Number} index - index of the slide
    *   @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag
    *   @param {Boolean} fromThumb - true if slide function called via thumbnail click
    */
  Plugin.prototype.slide = function (index, fromTouch, fromThumb) {
    var _prevIndex = this.$outer.find('.tglider-current').index()
    var _this = this

    // Prevent if multiple call
    // Required for hsh plugin
    if (_this.lGalleryOn && _prevIndex === index) {
      return
    }

    var _length = this.$slide.length

    var _time = _this.lGalleryOn ? this.s.speed : 0
    var _next = false
    var _prev = false

    if (_this.lgBusy) return

    if (this.s.download) {
      var _src
      if (_this.s.dynamic) {
        _src =
          _this.s.dynamicEl[index].downloadUrl !== false &&
          (_this.s.dynamicEl[index].downloadUrl || _this.s.dynamicEl[index].src)
      } else {
        _src =
          _this.$items.eq(index).attr('data-download-url') !== 'false' &&
          (_this.$items.eq(index).attr('data-download-url') ||
            _this.$items.eq(index).attr('href') ||
            _this.$items.eq(index).attr('data-src'))
      }

      if (_src) {
        $('#tglider-download').attr('href', _src)
        _this.$outer.removeClass('tglider-hide-download')
      } else {
        _this.$outer.addClass('tglider-hide-download')
      }
    }

    this.$el.trigger('onBeforeSlide.lg', [
      _prevIndex,
      index,
      fromTouch,
      fromThumb,
    ])

    _this.lgBusy = true

    clearTimeout(_this.hideBartimeout)

    // Add title if this.s.appendSubHtmlTo === tglider-sub-html
    if (this.s.appendSubHtmlTo === '.tglider-sub-html') {
      // wait for slide animation to complete
      setTimeout(function () {
        _this.addHtml(index)
      }, _time)
    }

    this.arrowDisable(index)

    if (!fromTouch) {
      // remove all transitions
      _this.$outer.addClass('tglider-no-trans')

      this.$slide.removeClass('tglider-prev-slide tglider-next-slide')

      if (index < _prevIndex) {
        _prev = true
        if (
          index === 0 &&
          _prevIndex === _length - 1 &&
          this.lastMove !== 'prev' &&
          !fromThumb
        ) {
          _prev = false
          _next = true
        }
      } else if (index > _prevIndex) {
        _next = true
        if (
          index === _length - 1 &&
          _prevIndex === 0 &&
          this.lastMove !== 'next' &&
          !fromThumb
        ) {
          _prev = true
          _next = false
        }
      }

      if (_prev) {
        //console.log('prev key', _this.lastMove, index, _prevIndex)
        //prevslide
        this.$slide.eq(index).addClass('tglider-prev-slide')
        this.$slide.eq(_prevIndex).addClass('tglider-next-slide')
      } else if (_next) {
        //console.log('next key', _this.lastMove, index, _prevIndex)
        // next slide
        this.$slide.eq(index).addClass('tglider-next-slide')
        this.$slide.eq(_prevIndex).addClass('tglider-prev-slide')
      }

      // give 50 ms for browser to add/remove class
      setTimeout(function () {
        _this.$slide.removeClass('tglider-current')

        //_this.$slide.eq(_prevIndex).removeClass('tglider-current');
        _this.$slide.eq(index).addClass('tglider-current')

        // reset all transitions
        _this.$outer.removeClass('tglider-no-trans')
      }, 50)
    } else {
      var touchPrev = index - 1
      var touchNext = index + 1

      if (touchPrev < 0) touchPrev = 0
      if (touchNext >= _length) touchNext = _length - 1

      if (_prevIndex === _length - 1 && index === 0) {
        // next slide
        if (this.lastMove == 'next') {
          touchPrev = _length - 1
          touchNext = 0
        } else {
          touchPrev = 0
          touchNext = _length - 1
        }
      } else if (_prevIndex === 0 && index === _length - 1) {
        // prev slide
        if (this.lastMove == 'prev') {
          touchPrev = _length - 1
          touchNext = 0
        } else {
          touchPrev = 0
          touchNext = _length - 1
        }
      }

      //console.log('touch '+this.lastMove+'('+(_length-1)+')', _prevIndex, index, touchPrev, touchNext)

      if (touchPrev === touchNext) {
        if (this.lastMove == 'prev') {
          touchPrev = false
        } else {
          touchNext = false
        }
      }

      this.$slide.removeClass(
        'tglider-prev-slide tglider-current tglider-next-slide'
      )

      if (touchPrev !== false) {
        if (touchPrev !== index && touchPrev !== _prevIndex) {
          // Prevent out of frame image from visibly sliding in the background
          _this.$slide.eq(touchPrev).addClass('tglider-prev-slide no-trans')
          setTimeout(function () {
            _this.$slide.eq(touchPrev).removeClass('no-trans')
          }, this.s.speed + 50)
        } else {
          _this.$slide.eq(touchPrev).addClass('tglider-prev-slide')
        }
      }

      if (touchNext !== false) {
        if (touchNext !== index && touchNext !== _prevIndex) {
          // Prevent out of frame image from visibly sliding in the background
          _this.$slide.eq(touchNext).addClass('tglider-next-slide no-trans')
          setTimeout(function () {
            _this.$slide.eq(touchNext).removeClass('no-trans')
          }, this.s.speed + 50)
        } else {
          _this.$slide.eq(touchNext).addClass('tglider-next-slide')
        }
      }

      _this.$slide.eq(index).addClass('tglider-current')
    }

    if (_this.lGalleryOn) {
      setTimeout(function () {
        _this.loadContent(index, true, 0)
      }, this.s.speed + 50)

      setTimeout(function () {
        _this.lgBusy = false
        _this.$el.trigger('onAfterSlide.lg', [
          _prevIndex,
          index,
          fromTouch,
          fromThumb,
        ])
      }, this.s.speed)
    } else {
      _this.loadContent(index, true, _this.s.backdropDuration)

      _this.lgBusy = false
      _this.$el.trigger('onAfterSlide.lg', [
        _prevIndex,
        index,
        fromTouch,
        fromThumb,
      ])
    }

    _this.lGalleryOn = true

    if (this.s.counter) {
      $('#tglider-counter-current').text(index + 1)
    }
  }

  /**
   *  @desc Go to next slide
   *  @param {Boolean} fromTouch - true if slide function called via touch event
   */
  Plugin.prototype.goToNextSlide = function (fromTouch) {
    var _this = this
    _this.lastMove = 'next'
    if (!_this.lgBusy) {
      if (_this.index + 1 < _this.$slide.length) {
        _this.index++
        _this.$el.trigger('onBeforeNextSlide.lg', [_this.index])
        _this.slide(_this.index, fromTouch, false)
      } else {
        if (_this.s.loop) {
          _this.index = 0
          _this.$el.trigger('onBeforeNextSlide.lg', [_this.index])
          _this.slide(_this.index, fromTouch, false)
        } else if (_this.s.slideEndAnimatoin) {
          _this.$outer.addClass('tglider-right-end')
          setTimeout(function () {
            _this.$outer.removeClass('tglider-right-end')
          }, 400)
        }
      }
    }
  }

  /**
   *  @desc Go to previous slide
   *  @param {Boolean} fromTouch - true if slide function called via touch event
   */
  Plugin.prototype.goToPrevSlide = function (fromTouch) {
    var _this = this
    _this.lastMove = 'prev'
    if (!_this.lgBusy) {
      if (_this.index > 0) {
        _this.index--
        _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch])
        _this.slide(_this.index, fromTouch, false)
      } else {
        if (_this.s.loop) {
          _this.index = _this.$items.length - 1
          _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch])
          _this.slide(_this.index, fromTouch, false)
        } else if (_this.s.slideEndAnimatoin) {
          _this.$outer.addClass('tglider-left-end')
          setTimeout(function () {
            _this.$outer.removeClass('tglider-left-end')
          }, 400)
        }
      }
    }
  }

  Plugin.prototype.keyPress = function () {
    var _this = this
    if (this.$items.length > 1) {
      $(window).on('keyup.lg', function (e) {
        if (_this.$items.length > 1) {
          if (e.keyCode === 37) {
            e.preventDefault()
            _this.goToPrevSlide()
          }

          if (e.keyCode === 39) {
            e.preventDefault()
            _this.goToNextSlide()
          }
        }
      })
    }

    $(window).on('keydown.lg', function (e) {
      if (_this.s.escKey === true && e.keyCode === 27) {
        e.preventDefault()
        if (!_this.$outer.hasClass('tglider-thumb-open')) {
          _this.destroy()
        } else {
          _this.$outer.removeClass('tglider-thumb-open')
        }
      }
    })
  }

  Plugin.prototype.arrow = function () {
    var _this = this
    this.$outer.find('.tglider-prev').on('click.lg', function () {
      if (!$(this).hasClass('disabled')) _this.goToPrevSlide()
    })

    this.$outer.find('.tglider-next').on('click.lg', function () {
      if (!$(this).hasClass('disabled')) _this.goToNextSlide()
    })
  }

  Plugin.prototype.arrowDisable = function (index) {
    // Disable arrows if s.hideControlOnEnd is true
    if (!this.s.loop && this.s.hideControlOnEnd) {
      if (index + 1 < this.$slide.length) {
        this.$outer
          .find('.tglider-next')
          .removeAttr('disabled')
          .removeClass('disabled')
      } else {
        this.$outer
          .find('.tglider-next')
          .attr('disabled', 'disabled')
          .addClass('disabled')
      }

      if (index > 0) {
        this.$outer
          .find('.tglider-prev')
          .removeAttr('disabled')
          .removeClass('disabled')
      } else {
        this.$outer
          .find('.tglider-prev')
          .attr('disabled', 'disabled')
          .addClass('disabled')
      }
    }
  }

  Plugin.prototype.setTranslate = function ($el, xValue, yValue) {
    // jQuery supports Automatic CSS prefixing since jQuery 1.8.0
    if (this.s.useLeft) {
      $el.css('left', xValue)
    } else {
      $el.css({
        transform: 'translate3d(' + xValue + 'px, ' + yValue + 'px, 0px)',
      })
    }
  }

  Plugin.prototype.touchMove = function (startCoords, endCoords) {
    var distance = endCoords - startCoords

    if (distance > 0) this.lastMove = 'next'
    else this.lastMove = 'prev'

    if (Math.abs(distance) > 15) {
      // reset opacity and transition duration
      this.$outer.addClass('tglider-dragging')

      // move current slide
      this.setTranslate(this.$slide.eq(this.index), distance, 0)

      // move next and prev slide with current slide
      this.setTranslate(
        $('.tglider-prev-slide'),
        -this.$slide.eq(this.index).width() + distance,
        0
      )
      this.setTranslate(
        $('.tglider-next-slide'),
        this.$slide.eq(this.index).width() + distance,
        0
      )
    }
  }

  Plugin.prototype.touchEnd = function (distance) {
    var _this = this

    // keep slide animation for any mode while dragg/swipe
    if (_this.s.mode !== 'tglider-slide') {
      _this.$outer.addClass('tglider-slide')
    }

    this.$slide
      .not('.tglider-current, .tglider-prev-slide, .tglider-next-slide')
      .css('opacity', '0')

    // set transition duration
    setTimeout(function () {
      _this.$outer.removeClass('tglider-dragging')
      if (distance < 0 && Math.abs(distance) > _this.s.swipeThreshold) {
        _this.goToNextSlide(true)
      } else if (distance > 0 && Math.abs(distance) > _this.s.swipeThreshold) {
        _this.goToPrevSlide(true)
      } else if (Math.abs(distance) < 5) {
        // Trigger click if distance is less than 5 pix
        _this.$el.trigger('onSlideClick.lg')
      }

      _this.$slide.removeAttr('style')
    })

    // remove slide class once drag/swipe is completed if mode is not slide
    setTimeout(function () {
      if (
        !_this.$outer.hasClass('tglider-dragging') &&
        _this.s.mode !== 'tglider-slide'
      ) {
        _this.$outer.removeClass('tglider-slide')
      }
    }, _this.s.speed + 100)
  }

  Plugin.prototype.enableSwipe = function () {
    var _this = this
    var startCoords = 0
    var endCoords = 0
    var isMoved = false

    if (_this.s.enableSwipe && _this.isTouch && _this.doCss()) {
      _this.$slide.on('touchstart.lg', function (e) {
        if (!_this.$outer.hasClass('tglider-zoomed') && !_this.lgBusy) {
          e.preventDefault()
          _this.manageSwipeClass()
          startCoords = e.originalEvent.targetTouches[0].pageX
        }
      })

      _this.$slide.on('touchmove.lg', function (e) {
        if (!_this.$outer.hasClass('tglider-zoomed')) {
          e.preventDefault()
          endCoords = e.originalEvent.targetTouches[0].pageX
          _this.touchMove(startCoords, endCoords)
          isMoved = true
        }
      })

      _this.$slide.on('touchend.lg', function () {
        if (!_this.$outer.hasClass('tglider-zoomed')) {
          if (isMoved) {
            isMoved = false
            _this.touchEnd(endCoords - startCoords)
          } else {
            _this.$el.trigger('onSlideClick.lg')
          }
        }
      })
    }
  }

  Plugin.prototype.enableDrag = function () {
    var _this = this
    var startCoords = 0
    var endCoords = 0
    var isDraging = false
    var isMoved = false
    if (_this.s.enableDrag && !_this.isTouch && _this.doCss()) {
      _this.$slide.on('mousedown.lg', function (e) {
        // execute only on .tglider-object
        if (!_this.$outer.hasClass('tglider-zoomed')) {
          if (
            $(e.target).hasClass('tglider-object') ||
            $(e.target).hasClass('tglider-video-play')
          ) {
            e.preventDefault()

            if (!_this.lgBusy) {
              _this.manageSwipeClass()
              startCoords = e.pageX
              isDraging = true

              // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
              _this.$outer.scrollLeft += 1
              _this.$outer.scrollLeft -= 1

              // *

              _this.$outer
                .removeClass('tglider-grab')
                .addClass('tglider-grabbing')

              _this.$el.trigger('onDragstart.lg')
            }
          }
        }
      })

      $(window).on('mousemove.lg', function (e) {
        if (isDraging) {
          isMoved = true
          endCoords = e.pageX
          _this.touchMove(startCoords, endCoords)
          _this.$el.trigger('onDragmove.lg')
        }
      })

      $(window).on('mouseup.lg', function (e) {
        if (isMoved) {
          isMoved = false
          _this.touchEnd(endCoords - startCoords)
          _this.$el.trigger('onDragend.lg')
        } else if (
          $(e.target).hasClass('tglider-object') ||
          $(e.target).hasClass('tglider-video-play')
        ) {
          _this.$el.trigger('onSlideClick.lg')
        }

        // Prevent execution on click
        if (isDraging) {
          isDraging = false
          _this.$outer.removeClass('tglider-grabbing').addClass('tglider-grab')
        }
      })
    }
  }

  Plugin.prototype.manageSwipeClass = function () {
    var touchNext = this.index + 1
    var touchPrev = this.index - 1
    var length = this.$slide.length
    if (this.s.loop) {
      if (this.index === 0) {
        touchPrev = length - 1
      } else if (this.index === length - 1) {
        touchNext = 0
      }
    }

    this.$slide.removeClass('tglider-next-slide tglider-prev-slide')
    if (touchPrev > -1) {
      this.$slide.eq(touchPrev).addClass('tglider-prev-slide')
    }

    this.$slide.eq(touchNext).addClass('tglider-next-slide')
  }

  Plugin.prototype.mousewheel = function () {
    var _this = this
    _this.$outer.on('mousewheel.lg', function (e) {
      if (!e.deltaY) {
        return
      }

      if (e.deltaY > 0) {
        _this.goToPrevSlide()
      } else {
        _this.goToNextSlide()
      }

      e.preventDefault()
    })
  }

  Plugin.prototype.closeGallery = function () {
    var _this = this
    var mousedown = false
    this.$outer.find('.tglider-close').on('click.lg', function () {
      _this.destroy()
    })

    if (_this.s.closable) {
      // If you drag the slide and release outside gallery gets close on chrome
      // for preventing this check mousedown and mouseup happened on .tglider-item or tglider-outer
      _this.$outer.on('mousedown.lg', function (e) {
        if (
          $(e.target).is('.tglider-outer') ||
          $(e.target).is('.tglider-item ') ||
          $(e.target).is('.tglider-img-wrap')
        ) {
          mousedown = true
        } else {
          mousedown = false
        }
      })

      _this.$outer.on('mouseup.lg', function (e) {
        if (
          $(e.target).is('.tglider-outer') ||
          $(e.target).is('.tglider-item ') ||
          ($(e.target).is('.tglider-img-wrap') && mousedown)
        ) {
          if (!_this.$outer.hasClass('tglider-dragging')) {
            _this.destroy()
          }
        }
      })
    }
  }

  Plugin.prototype.destroy = function (d) {
    var _this = this

    if (!d) {
      _this.$el.trigger('onBeforeClose.lg')
    }

    $(window).scrollTop(_this.prevScrollTop)

    /**
     * if d is false or undefined destroy will only close the gallery
     * plugins instance remains with the element
     *
     * if d is true destroy will completely remove the plugin
     */

    if (d) {
      if (!_this.s.dynamic) {
        // only when not using dynamic mode is $items a jquery collection
        this.$items.off('click.lg click.lgcustom')
      }

      $.removeData(_this.el, 'tangibleGlider')
    }

    // Unbind all events added by tangibleGlider
    this.$el.off('.lg.tm')

    // Distroy all tangibleGlider modules
    $.each($.fn.tangibleGlider.modules, function (key) {
      if (_this.modules[key]) {
        _this.modules[key].destroy()
      }
    })

    this.lGalleryOn = false

    clearTimeout(_this.hideBartimeout)
    this.hideBartimeout = false
    $(window).off('.lg')
    $('body').removeClass('tglider-on tglider-from-hash')

    if (_this.$outer) {
      _this.$outer.removeClass('tglider-visible')
    }

    $('.tglider-backdrop').removeClass('in')

    setTimeout(function () {
      if (_this.$outer) {
        _this.$outer.remove()
      }

      $('.tglider-backdrop').remove()

      if (!d) {
        _this.$el.trigger('onCloseAfter.lg')
      }
    }, _this.s.backdropDuration + 50)
  }

  $.fn.tangibleGlider = function (options) {
    return this.each(function () {
      if (!$.data(this, 'tangibleGlider')) {
        $.data(this, 'tangibleGlider', new Plugin(this, options))
      } else {
        // Already initialized
        // try {
        //   $(this).data('tangibleGlider').init()
        // } catch (err) {
        //   console.error('tangibleGlider has not initiated properly')
        // }
      }
    })
  }

  $.fn.tangibleGlider.modules = {}
})(jQuery, window, document)
